1 module mpdec.decimal; 2 3 import mpdec.deimos; 4 import core.stdc.stdio:printf; 5 import std..string:toStringz,fromStringz; 6 import std.stdio; 7 import core.memory; 8 import core.stdc.stdlib; 9 10 /* 11 12 MIT License 13 14 Copyright (c) 2021 Pablo De Nápoli 15 16 Permission is hereby granted, free of charge, to any person obtaining a copy 17 of this software and associated documentation files (the "Software"), to deal 18 in the Software without restriction, including without limitation the rights 19 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 copies of the Software, and to permit persons to whom the Software is 21 furnished to do so, subject to the following conditions: 22 23 The above copyright notice and this permission notice shall be included in all 24 copies or substantial portions of the Software. 25 26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 SOFTWARE. 33 34 */ 35 36 mpd_context_t decimal_ctx; 37 38 void init_decimal(int prec) { 39 printf("Using libmpdec version %s \n",mpd_version); 40 mpd_init(&decimal_ctx,prec); 41 } 42 43 void init_ieee_decimal(int bits) { 44 printf("Using libmpdec version %s \n",mpd_version); 45 mpd_ieee_context(&decimal_ctx, bits); 46 } 47 48 struct Decimal{ 49 mpd_t* value; 50 private string name; 51 52 //@disable this(); 53 54 this(mpd_t* v) 55 { 56 value=v; 57 } 58 59 this(Decimal original) 60 { 61 //debug writeln("Call copy constructor"); 62 value=mpd_qncopy(original.value); 63 } 64 65 this(this) 66 { 67 //debug writeln("Calling this(this)"); 68 if (value) 69 value = mpd_qncopy(value); 70 } 71 72 this(string s) 73 { 74 value=mpd_new(&decimal_ctx); 75 immutable(char)* c_string = toStringz(s); 76 GC.addRoot(cast(void*)c_string); 77 GC.setAttr(cast(void*)c_string, GC.BlkAttr.NO_MOVE); 78 mpd_set_string(value,c_string,&decimal_ctx); 79 GC.removeRoot(cast(void*)c_string); 80 GC.clrAttr(cast(void*)c_string, GC.BlkAttr.NO_MOVE); 81 } 82 83 this(int x) 84 { 85 value=mpd_new(&decimal_ctx); 86 mpd_set_i32(value, x, &decimal_ctx); 87 } 88 89 this(long x) 90 { 91 value=mpd_new(&decimal_ctx); 92 mpd_set_i64(value, x, &decimal_ctx); 93 } 94 95 ~this() 96 { 97 //debug writeln("Calling mpd_del value=",value); 98 if (value) 99 mpd_del(value); 100 value=null; 101 } 102 103 // a string representation, used by write. 104 string toString() const 105 { 106 if (value) 107 { 108 char* s= mpd_to_eng(value, 0); // 0 = exponential in lower case 109 auto s_string = cast(string) fromStringz(s); 110 return s_string; 111 } 112 else return "null"; 113 } 114 115 116 bool opEquals(Decimal rhs) const { 117 if (!value || !rhs.value) 118 return false; 119 return mpd_cmp(value,rhs.value,&decimal_ctx)==0; 120 } 121 122 123 // unary operator overloading 124 125 Decimal opUnary(string op)() 126 { 127 mpd_t* result; 128 if (!value) 129 return this; 130 static if (op == "-") 131 { 132 result=mpd_new(&decimal_ctx); 133 mpd_minus(result,value,&decimal_ctx); 134 return Decimal(result); 135 } 136 else static if (op == "+") 137 { 138 result=mpd_new(&decimal_ctx); 139 mpd_plus(result,value,&decimal_ctx); 140 return Decimal(result); 141 } 142 else static if (op == "++") 143 { 144 mpd_add_i32(value, value, 1,&decimal_ctx); 145 return this; 146 } 147 else static if (op == "--") 148 { 149 mpd_sub_i32(value, value, 1,&decimal_ctx); 150 return this; 151 } 152 else static assert(0, "Operator "~op~" not implemented"); 153 } 154 155 156 157 // binary operator overloading 158 159 Decimal opBinary(string op)(Decimal rhs) 160 { 161 if (!value || !rhs.value) 162 return this; 163 mpd_t* result= mpd_new(&decimal_ctx); 164 static if (op == "+") 165 { 166 mpd_add(result,value,rhs.value,&decimal_ctx); 167 } 168 else static if (op == "-") 169 { 170 mpd_sub(result,value,rhs.value,&decimal_ctx); 171 } 172 else static if (op == "*") 173 { 174 mpd_mul(result,value,rhs.value,&decimal_ctx); 175 } 176 else static if (op == "/") 177 { 178 mpd_div(result,value,rhs.value,&decimal_ctx); 179 } 180 else static if (op == "%") 181 { 182 mpd_rem(result,value,rhs.value,&decimal_ctx); 183 } 184 else static if (op == "^^") 185 { 186 mpd_pow(result,value,rhs.value,&decimal_ctx); 187 } 188 else static assert(0, "Operator "~op~" not implemented"); 189 190 return Decimal(result); 191 } 192 193 // assign operator overloading 194 195 Decimal opOpAssign(string op)(Decimal rhs) 196 { 197 if (!value || !rhs.value) 198 return this; 199 static if (op == "+") 200 { 201 mpd_add(value,value,rhs.value,&decimal_ctx); 202 } 203 else static if (op == "-") 204 { 205 // debug write("value="); 206 mpd_print(value); 207 // debug write("rhs.value="); 208 mpd_print(rhs.value); 209 mpd_sub(value,value,rhs.value,&decimal_ctx); 210 } 211 else static if (op == "/") 212 { 213 mpd_div(value,value,rhs.value,&decimal_ctx); 214 } 215 else static if (op == "%") 216 { 217 mpd_rem(value,value,rhs.value,&decimal_ctx); 218 } 219 else static if (op == "^^") 220 { 221 mpd_pow(value,value,rhs.value,&decimal_ctx); 222 } 223 else static assert(0, "opOpAssign: Operator "~op~" not implemented"); 224 return this; 225 } 226 227 // comparison operator overloading 228 229 const int opCmp(const Decimal rhs){ 230 if (!value || !rhs.value) 231 return false; 232 return mpd_cmp(value,rhs.value,&decimal_ctx); 233 } 234 235 bool isfinite() 236 { 237 if (!value) return false; 238 return cast(bool) mpd_isfinite(value); 239 } 240 241 bool isinfinite() 242 { 243 if (!value) return false; 244 return cast(bool) mpd_isinfinite(value); 245 } 246 247 bool isnan() 248 { 249 if (!value) return false; 250 return cast(bool) mpd_isnan(value); 251 } 252 253 bool isnegative() 254 { 255 if (!value) return false; 256 return cast(bool) mpd_isnegative(value); 257 } 258 259 bool ispositive() 260 { 261 if (!value) return false; 262 return cast(bool) mpd_ispositive(value); 263 } 264 265 bool isqnan() 266 { 267 if (!value) return false; 268 return cast(bool) mpd_isqnan(value); 269 } 270 271 bool issigned() 272 { 273 if (!value) return false; 274 return cast(bool) mpd_issigned(value); 275 } 276 277 bool issnan() 278 { 279 if (!value) return false; 280 return cast(bool) mpd_issnan(value); 281 } 282 283 bool isspecial() 284 { 285 if (!value) return false; 286 return cast(bool) mpd_isspecial(value); 287 } 288 289 bool iszero() 290 { 291 if (!value) return false; 292 return cast(bool) mpd_iszero(value); 293 } 294 295 bool is_nonnegative() 296 { 297 return iszero() ||ispositive() ; 298 } 299 300 bool is_nonpositive() 301 { 302 return iszero()||isnegative(); 303 } 304 } 305 306 Decimal decimal_abs(Decimal x) 307 { 308 mpd_t* result; 309 result=mpd_new(&decimal_ctx); 310 mpd_abs(result,x.value,&decimal_ctx); 311 return Decimal(result); 312 }